using System;
using System.Collections;
using System.IO;
using Org.BouncyCastle.Bcpg.OpenPgp;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Bcpg;

using System.Text;
using Org.BouncyCastle.Bcpg.Sig;
using Org.BouncyCastle.Asn1.Utilities;

using Org.BouncyCastle.Utilities.Encoders;
using Pbdms.Common.SharedVariables;
namespace Pbdms.Common.CryptoUtils
{
    public class Verifier
    {
        
        private PublicKeysControl publicKeyControl;
       
        public Verifier()
        {
            publicKeyControl = null;
        }
        public Verifier(PublicKeysControl publicKeyControl)
        {
            this.publicKeyControl = publicKeyControl;
        }
        #region verison 2
        public string VerifyFile(string fileout, string fileIn,PgpPublicKey key)
        {
            Stream dIn = null;
            
            Stream inputStreamtemp = null;
            Stream inputStream = null;
            try
            {
                inputStreamtemp = File.OpenRead(fileIn);
            }
            catch (Exception ex)
            {
                inputStreamtemp.Close();
                throw new Exception("unable to read the file " + fileIn);
            }
            try
            {
                inputStream = PgpUtilities.GetDecoderStream(inputStreamtemp);
            }
            catch (Exception ex)
            {
                inputStream.Close();
                throw new Exception("Error in opening the file");
            }
            Stream fos = null;
            try
            {
                fos = File.Create(fileout);
            }
            catch (Exception ex)
            {
                fos.Close();
                throw new Exception("unable to open the file");
            }

            try
            {


                PgpObjectFactory pgpFact = new PgpObjectFactory(inputStream);
                PgpCompressedData c1 = (PgpCompressedData)pgpFact.NextPgpObject();
                pgpFact = new PgpObjectFactory(c1.GetDataStream());

                PgpOnePassSignatureList p1 = (PgpOnePassSignatureList)pgpFact.NextPgpObject();
                PgpOnePassSignature ops = p1[0];

                PgpLiteralData p2 = (PgpLiteralData)pgpFact.NextPgpObject();
                dIn = p2.GetInputStream();

                
                if (key == null)
                {
                    throw new Exception("there is no public key to verify with the signature. Public Key with this id: " + ops.KeyId.ToString("X"));
                }
                

                ops.InitVerify(key);

                int ch;
                while ((ch = dIn.ReadByte()) >= 0)
                {
                    ops.Update((byte)ch);
                    fos.WriteByte((byte)ch);
                }
                PgpSignatureList p3 = (PgpSignatureList)pgpFact.NextPgpObject();
                PgpSignature firstSig = p3[0];
                if (ops.Verify(firstSig))
                {

                    return (firstSig.KeyId.ToString("X"));
                }
                else
                {
                    throw new Exception("signature verification failed. " + firstSig.KeyId.ToString("X"));
                }
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
            finally
            {

                fos.Close();
                dIn.Close();
                inputStream.Close();
                inputStreamtemp.Close();
            }
        }
        //just verify the signature
        public Boolean VerifySignature(PgpSignature sign, PgpPublicKey realKey)
        {
            sign.InitVerify(realKey);
            if (sign.Verify())
            {
                return true;
            }
            else
            {

                return false;
            }
        }

        public Boolean VerifySignature(PgpSignature sign, PgpPublicKey realKey,string keyid)
        {
            sign.InitVerify(realKey);
            if (sign.Verify())
            {
                foreach (NotationData data in sign.GetHashedSubPackets().GetNotationDataOccurences())
                {
                    
                    if (data.GetNotationName().Equals("keyID"))
                    {
                        if (data.GetNotationValue().Equals(keyid))
                        {
                            return true;
                        }
                        else
                        {
                            Console.WriteLine(data.GetNotationValue());
                        }
                    }

                    break;
                }
               
                return false;
            }
            else
            {

                return false;
            }
        }

        
        //method that verifing the message passed in and return the decoded message 
        public Common.DataObject.VerifyObj VerifyMessage(string message)

        {
            Stream dIn = null;

            MemoryStream inputStreamtemp = new MemoryStream(); 
            Stream inputStream = null;
            try
            {
                // set messageto memory 
                System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
                byte[] data = encoding.GetBytes(message);
                int start = 0;
                while (start < data.Length)
                {
                    inputStreamtemp.WriteByte(data[start]);
                    start++;
                }

                inputStreamtemp.Seek(0, SeekOrigin.Begin);

            }
            catch (Exception ex)
            {
                inputStreamtemp.Close();
                throw new Exception("unable to read the file ");
            }
            try
            {
                inputStream = PgpUtilities.GetDecoderStream(inputStreamtemp);
            }
            catch (Exception ex)
            {
                inputStream.Close();
                throw new Exception("Error in opening the file");
            }
            Stream fos = null;
            try
            {
                //fos = File.Create("c:\\goh2.txt");
                fos = new MemoryStream();
            }
            catch (Exception ex)
            {
                fos.Close();
                throw new Exception("unable to open the file");
            }

            try
            {


                PgpObjectFactory pgpFact = new PgpObjectFactory(inputStream);
                PgpCompressedData c1 = (PgpCompressedData)pgpFact.NextPgpObject();
                pgpFact = new PgpObjectFactory(c1.GetDataStream());

                PgpOnePassSignatureList p1 = (PgpOnePassSignatureList)pgpFact.NextPgpObject();
                PgpOnePassSignature ops = p1[0];

                PgpLiteralData p2 = (PgpLiteralData)pgpFact.NextPgpObject();
                dIn = p2.GetInputStream();


                PgpPublicKey key = publicKeyControl.getPublicKey(ops.KeyId.ToString("X"));
                if (key == null)
                {
                    throw new Exception("there is no public key to verify with the signature. Public Key with this id: " + ops.KeyId.ToString("X"));
                }


                ops.InitVerify(key);

                int ch;
                while ((ch = dIn.ReadByte()) >= 0)
                {
                    ops.Update((byte)ch);
                    fos.WriteByte((byte)ch);
                }
                PgpSignatureList p3 = (PgpSignatureList)pgpFact.NextPgpObject();
                PgpSignature firstSig = p3[0];
                if (ops.Verify(firstSig) == true)
                {
                    //convert to string
                    fos.Seek(0, SeekOrigin.Begin);

                    int start2 = 0;
                    byte[] newBytes2 = new byte[fos.Length];
                    while (start2 < fos.Length)
                    {
                        newBytes2[start2] = (byte)fos.ReadByte();
                        start2++;
                    }
                    System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
                    Common.DataObject.VerifyObj verifyObj = new Pbdms.Common.DataObject.VerifyObj();
                    //assign to verify obj
                    verifyObj.Data = enc.GetString(newBytes2);
                    verifyObj.keyID = ops.KeyId.ToString("X");
                    //string str = ;
                    //str = str + " " + ops.KeyId.ToString("X");
                    return verifyObj;
                }
                else
                {
                    throw new Exception("signature verification failed. " + firstSig.KeyId.ToString("X"));
                }
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
               
            }
            finally
            {

                fos.Close();
                dIn.Close();
                inputStream.Close();
                inputStreamtemp.Close();
            }


        }
         
        public Common.DataObject.VerifyObj VerifyMessage(string message, string signature)
        {
            Stream inputStream = null;
            MemoryStream memSig = new MemoryStream();
            MemoryStream memMsg = new MemoryStream();
            try
            {
                // set messageto memory 
                System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
                byte[] data = encoding.GetBytes(signature);
                int start = 0;
                while (start < data.Length)
                {
                    memSig.WriteByte(data[start]);
                    start++;
                }

                memSig.Seek(0, SeekOrigin.Begin);

            }
            catch (Exception ex)
            {
                memSig.Close();
                throw new Exception("unable to read the signature ");
            }
            try
            {
                // set messageto memory 
                System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
                byte[] dataMsg = encoding.GetBytes(message);
                int startMsg = 0;
                while (startMsg < dataMsg.Length)
                {
                    memMsg.WriteByte(dataMsg[startMsg]);
                    startMsg++;
                }

                memMsg.Seek(0, SeekOrigin.Begin);

            }
            catch (Exception ex)
            {
                memMsg.Close();
                throw new Exception("unable to read the signature ");
            }
            inputStream = PgpUtilities.GetDecoderStream(memSig);

            PgpObjectFactory pgpFact = new PgpObjectFactory(inputStream);
            PgpSignatureList p3 = null;
            PgpObject o = pgpFact.NextPgpObject();
            if (o is PgpCompressedData)
            {
                PgpCompressedData c1 = (PgpCompressedData)o;
                pgpFact = new PgpObjectFactory(c1.GetDataStream());

                p3 = (PgpSignatureList)pgpFact.NextPgpObject();
            }
            else
            {
                p3 = (PgpSignatureList)o;
            }

          
            Stream dIn = memMsg;
            int ch;
            PgpSignature sig = p3[0];

            PgpPublicKey key = publicKeyControl.getPublicKey(sig.KeyId.ToString("X"));
            
            sig.InitVerify(key);
            while ((ch = dIn.ReadByte()) >= 0)
            {
                sig.Update((byte)ch);
            }
            dIn.Close();
            memMsg.Close();
            memSig.Close();
            inputStream.Close();
            if (sig.Verify())
            {
                Common.DataObject.VerifyObj verifyObj = new Pbdms.Common.DataObject.VerifyObj();
                verifyObj.keyID = sig.KeyId.ToString("X");
                return verifyObj;
                
            }
            else
            {
                throw new Exception("error verify the signature");
            }
        }
        #endregion
        /// <summary>
        /// verify bytes
        /// </summary>
        /// <param name="bytesToVerify"></param>
        /// <returns></returns>
        public Common.DataObject.VerifyObjMem VerifyBytes(MemoryStream bytesToVerify)
        {
            Stream dIn = null;

            MemoryStream inputStreamtemp = new MemoryStream();
            Stream inputStream = null;
          
            try
            {
                inputStream = PgpUtilities.GetDecoderStream(bytesToVerify);
            }
            catch (Exception ex)
            {
                inputStream.Close();
                return null;
            }
            MemoryStream fos = null;
            try
            {
                //fos = File.Create("c:\\goh2.txt");
                fos = new MemoryStream();
            }
            catch (Exception ex)
            {
                fos.Close();
                return null;
            }

            try
            {


                PgpObjectFactory pgpFact = new PgpObjectFactory(inputStream);
                PgpCompressedData c1 = (PgpCompressedData)pgpFact.NextPgpObject();
                pgpFact = new PgpObjectFactory(c1.GetDataStream());

                PgpOnePassSignatureList p1 = (PgpOnePassSignatureList)pgpFact.NextPgpObject();
                PgpOnePassSignature ops = p1[0];

                PgpLiteralData p2 = (PgpLiteralData)pgpFact.NextPgpObject();
                dIn = p2.GetInputStream();


                PgpPublicKey key = publicKeyControl.getPublicKey(ops.KeyId.ToString("X"));
                if (key == null)
                {
                    return null;
                }


                ops.InitVerify(key);

                int ch;
                while ((ch = dIn.ReadByte()) >= 0)
                {
                    ops.Update((byte)ch);
                    fos.WriteByte((byte)ch);
                }
                PgpSignatureList p3 = (PgpSignatureList)pgpFact.NextPgpObject();
                PgpSignature firstSig = p3[0];
                if (ops.Verify(firstSig) == true)
                {
                    //convert to string
                    fos.Seek(0, SeekOrigin.Begin);
                    Common.DataObject.VerifyObjMem verifyObjmem = new Pbdms.Common.DataObject.VerifyObjMem();
                    verifyObjmem.keyID = ops.KeyId.ToString("X");
                    verifyObjmem.MemData = fos;
                    return verifyObjmem;
                }
                else
                {
                    return null;
                }
            }
            catch (Exception ex)
            {
                return null;

            }
            finally
            {

                
                dIn.Close();
                inputStream.Close();
                inputStreamtemp.Close();
                bytesToVerify.Close();
            }


        }
        public string VerifyFile(string fileout, string fileIn)
        {
            Stream dIn = null;

            Stream inputStreamtemp = null;
            Stream inputStream = null;
            try
            {
                inputStreamtemp = File.OpenRead(fileIn);
            }
            catch (Exception ex)
            {
                inputStreamtemp.Close();
                throw new Exception("unable to read the file " + fileIn);
            }
            try
            {
                inputStream = PgpUtilities.GetDecoderStream(inputStreamtemp);
            }
            catch (Exception ex)
            {
                inputStream.Close();
                throw new Exception("Error in opening the file");
            }
            Stream fos = null;
            try
            {
                fos = File.Create(fileout);
            }
            catch (Exception ex)
            {
                fos.Close();
                throw new Exception("unable to open the file");
            }

            try
            {


                PgpObjectFactory pgpFact = new PgpObjectFactory(inputStream);
                PgpCompressedData c1 = (PgpCompressedData)pgpFact.NextPgpObject();
                pgpFact = new PgpObjectFactory(c1.GetDataStream());

                PgpOnePassSignatureList p1 = (PgpOnePassSignatureList)pgpFact.NextPgpObject();
                PgpOnePassSignature ops = p1[0];

                PgpLiteralData p2 = (PgpLiteralData)pgpFact.NextPgpObject();
                dIn = p2.GetInputStream();

                PgpPublicKey key =publicKeyControl.getPublicKey(ops.KeyId.ToString("X"));
                if (key == null)
                {
                    throw new Exception("there is no public key to verify with the signature. Public Key with this id: " + ops.KeyId.ToString("X"));
                }


                ops.InitVerify(key);

                int ch;
                while ((ch = dIn.ReadByte()) >= 0)
                {
                    ops.Update((byte)ch);
                    fos.WriteByte((byte)ch);
                }
                PgpSignatureList p3 = (PgpSignatureList)pgpFact.NextPgpObject();
                PgpSignature firstSig = p3[0];
                if (ops.Verify(firstSig))
                {

                    return (firstSig.KeyId.ToString("X"));
                }
                else
                {
                    throw new Exception("signature verification failed. " + firstSig.KeyId.ToString("X"));
                }
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
            finally
            {

                fos.Close();
                dIn.Close();
                inputStream.Close();
                inputStreamtemp.Close();
            }
        }
    }
}
